package jp.sourceforge.akjrcp.text_douga.views.syncsubimages;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import jp.sourceforge.akjrcp.commons.ui.EditableFileList;
import jp.sourceforge.akjrcp.commons.ui.FileDirChoicer;
import jp.sourceforge.akjrcp.commons.ui.AbstractFileDirChoicer.FileStatusChangeEvent;
import jp.sourceforge.akjrcp.commons.ui.AbstractFileDirChoicer.FileStatusChangeListener;
import jp.sourceforge.akjrcp.commons.ui.widget.LayoutDataBuilder;
import jp.sourceforge.akjrcp.commons.ui.widget.WidgetBuilder;
import jp.sourceforge.akjrcp.commons.util.ClipboardUtil;
import jp.sourceforge.akjrcp.commons.util.FileNameUtils;
import jp.sourceforge.akjrcp.ffmpeg.FFMpegUI;
import jp.sourceforge.akjrcp.subtitle.StandardSubObject;
import jp.sourceforge.akjrcp.subtitle.SubtitleUtils;
import jp.sourceforge.akjrcp.subtitle.srt.SRTList;
import jp.sourceforge.akjrcp.text_douga.parser.ParserUtils;
import jp.sourceforge.akjrcp.text_douga.parser.PropertyUtils;
import jp.sourceforge.akjrcp.text_douga.rcp.Messages;
import jp.sourceforge.akjrcp.text_douga.rcp.TextDougaView;
import jp.sourceforge.akjrcp.text_douga.views.syncsubimages.SyncSubBuilder.ResultData;
import jp.sourceforge.akjrcp.text_douga.views.syncsubimages.SyncSubBuilder.SyncImageData;
import jp.sourceforge.akjrcp.util.TimeUtils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;

import com.akjava.lib.swt.images.cashe.ResizedImageCache;
import com.akjava.lib.swt.ui.param.ParamTime;

public class SyncSubImageView extends ViewPart {
	public static Log log=LogFactory.getLog(SyncSubImageView.class);
	public static final String ID = SyncSubImageView.class.getName();

	private CCombo size;
	private CCombo fps;
	
	public String getSize(){
		return size.getText();
	}
	public String getFps(){
		return fps.getText();
	}
	
	private int imageIndex;
	private FileDirChoicer inputSubtitle;
	private ScrolledComposite scroll;
	private Composite composite;
	private Composite baseComposite;
	private EditableFileList beforeFiles;
	//private EditableFileList afterFiles;
	private FileDirChoicer inputAudio;
	private Button execButton;
	private ResizedImageCache imageCache;
	private int imgWidth=240;
	private int imgHeight=135;
	private Menu popUpMenu;
	private double audioOffset;
	private ParamTime offsetTime;
	public void createPartControl(Composite parent) {
		imageCache=new ResizedImageCache();
		imageCache.setWidth(imgWidth);
		imageCache.setHeight(imgHeight);
		imageCache.setMaxSize(100);
		Composite base=new Composite(parent,SWT.NULL);
		base.setLayout(new GridLayout());

		


		
		Composite fields=WidgetBuilder.createTwoGridLayoutComposite(base, SWT.NULL);

		size=createCCombo(fields,Messages.getString("exportimg.size"),new String[]{"","160x120","320x240","640x480","","720x480","","320x180","720x405","1280x720","","320x176","640x352"},SWT.NULL);
		//int w_h[]=TextDougaUtils.getDefaultSize();
		size.setText("320x176");//default preview mode
		
		
		fps=createCCombo(fields,Messages.getString("exportimg.fps"),new String[]{"","1","5","10","12","14.895","15","20","24","25","29.97","30"},SWT.NULL);
		fps.setText("5");//for slide show
		

		inputSubtitle = new FileDirChoicer(base,SWT.NULL,FileDirChoicer.FILE,Messages.getString("syncsub.subtitle"));
		inputSubtitle.setLayoutData(LayoutDataBuilder.fillHorizontalGridData());
		inputSubtitle.setFilterExtensions(FileNameUtils.toMixFilterExtensions(new String[]{"srt","txt"}));
		inputSubtitle.addFileListChangeListener(new FileStatusChangeListener(){

			@Override
			public void addList(FileStatusChangeEvent event) {
				loadSubtitleFile();
			}

			@Override
			public void removeList(FileStatusChangeEvent event) {
				// TODO Auto-generated method stub
				
			}});
	
		inputAudio = new FileDirChoicer(base,SWT.NULL,FileDirChoicer.FILE,Messages.getString("syncsub.audio"));
		inputAudio.setLayoutData(LayoutDataBuilder.fillHorizontalGridData());
		inputAudio.setFilterExtensions(FileNameUtils.toMixFilterExtensions(ParserUtils.audios));
		
		baseComposite = new Composite(base,SWT.NULL);
		baseComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		baseComposite.setLayout(new GridLayout(2,true));
		WidgetBuilder.createLabel(baseComposite, Messages.getString("syncsub.before"));
		Composite otherControler=WidgetBuilder.createGridLayoutComposite(baseComposite, SWT.NULL, 2, false);
		Composite files=WidgetBuilder.createGridLayoutComposite(baseComposite, SWT.NULL, 2, false);
		files.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		
		Label imgLabel=new Label(files,SWT.BORDER);
		
		beforeFiles = WidgetBuilder.createFileList(files,SWT.NULL,"*.gif;*.png;*.jpg;*.bmp");
		beforeFiles.setLayoutData(LayoutDataBuilder.hintGridData(-1, -1));
		beforeFiles.setShowNameOnly(true);
		beforeFiles.addPropertyChangeListener(new IPropertyChangeListener(){
			public void propertyChange(PropertyChangeEvent event) {
				updateStatus();
			}});
		
		offsetTime = new ParamTime(otherControler,SWT.BORDER,"time",Messages.getString("syncsub.offsettime"));
		imgLabel.setLayoutData(LayoutDataBuilder.hintGridData(imgWidth, imgHeight));
		UpdateLabelListener labelListener=new UpdateLabelListener(beforeFiles,imgLabel);
		beforeFiles.addPropertyChangeListener(labelListener);
		beforeFiles.addSelectionChangedListener(labelListener);
		//beforeFiles.addSelectionChangedListener();
		/*
		afterFiles = WidgetBuilder.createFileList(baseComposite,SWT.NULL,"*.gif;*.png;*.jpg;*.bmp");
		afterFiles.setLayoutData(LayoutDataBuilder.hintGridData(-1, 20));
		afterFiles.addPropertyChangeListener(new IPropertyChangeListener(){
			public void propertyChange(PropertyChangeEvent event) {
				updateStatus();
			}});
			*/
		
		scroll = new ScrolledComposite(base,SWT.V_SCROLL|SWT.BORDER);
		GridData gdata=new GridData(GridData.FILL_BOTH);
		gdata.grabExcessVerticalSpace=true;
		//gdata.minimumHeight=200;
		scroll.setLayoutData(gdata);
		
	
		
		composite = new Composite(scroll,SWT.NULL);
		composite.setLayoutData(new GridData(GridData.FILL_BOTH));
		composite.setLayout(new GridLayout(1,false));
		

		scroll.setContent(composite);
		scroll.setMinSize(SWT.DEFAULT,250);//default
		
		scroll.setExpandHorizontal(true);
		scroll.setExpandVertical(true);
		
		

		execButton = WidgetBuilder.createButton(base, "exec");
		execButton.setEnabled(false);
		execButton.addSelectionListener(new SelectionListener(){

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
			}

			@Override
			public void widgetSelected(SelectionEvent e) {
				exec();
			}});
		
       
		createPopupMenus(base);
	}
	
	private void createPopupMenus(Composite base){
		   popUpMenu = new Menu(getSite().getShell(), SWT.POP_UP);
			base.setMenu(popUpMenu);
			
			MenuItem loadData=WidgetBuilder.createPushMenu(popUpMenu, "load from clipboard");
			loadData.addSelectionListener(new SelectionListener(){

				@Override
				public void widgetDefaultSelected(SelectionEvent e) {
					// TODO Auto-generated method stub
					
				}

				@Override
				public void widgetSelected(SelectionEvent e) {
					String text=ClipboardUtil.getCurrentText(getSite().getShell().getDisplay());
					text=text.replace("\r\n", "\n");
					loadText(text);
				}});
	}
	
	public void loadSubtitleFile(){
		File file=inputSubtitle.getFile();
		if(file.getName().toLowerCase().endsWith(".srt")){
			//srt
			try {
				beforeFiles.clear();
				SRTList list=SubtitleUtils.loadSrt(file,"MS932");
				List<StandardSubObject> subs=list.convertStandardSubtitleDataList();
				Control[] controls=composite.getChildren();
				for (int i = 0; i < controls.length; i++) {
					controls[i].dispose();
				}
				log.info("disposed all");
				for(int i=0;i<subs.size();i++){
					SubtitleData data=new SubtitleData(composite,SWT.BORDER);
					data.setData(subs.get(i));
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			composite.layout();
			Control[] controls=composite.getChildren();
			int total=0;
			for (int i = 0; i < controls.length; i++) {
				total+=controls[i].getBounds().height;
			}
			total+=6*controls.length;
			//System.out.println(total+250);
			
			scroll.setMinSize(SWT.DEFAULT, total);
		}
	}
	public  class UpdateLabelListener implements IPropertyChangeListener,ISelectionChangedListener{
		private Label target;
		private EditableFileList fileList;
		public UpdateLabelListener(EditableFileList fileList,Label target){
			this.target=target;
			this.fileList=fileList;
		}
		public void updateImage(){

			if(fileList.getFileList()==null || fileList.getFileList().length==0){
				log.trace("no image");
				target.setImage(null);//no image;
			}else{
				log.info("property change:"+fileList.getFileList().length);
				File selections[]=fileList.getSelectionFiles();
				Image img;
				if(selections.length==0){
				img=imageCache.loadImage(fileList.getFileList()[fileList.getFileList().length-1]);//select last
				}else{
				img=imageCache.loadImage(selections[0]);
				}
				if(img!=null){
					log.trace(img.getBounds());
				}
				target.setImage(img);
			}
		}
		@Override
		public void propertyChange(PropertyChangeEvent event) {
			updateImage();
		}
		@Override
		public void selectionChanged(SelectionChangedEvent event) {
			updateImage();
		}
		
	}
	
	public void exec(){
		TextDougaView view=(TextDougaView) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findView(TextDougaView.ID);
		
		//change mode
		
		view.setExportType(TextDougaView.AVI);
		view.setExportMode(TextDougaView.MODE_MUX);
		String text="";		
		if(this.getSize().length()>0){
			text+="#export_size="+this.getSize();
		}else{
			text+="#export_size="+"1280x736";
		}
		text+="\n";
		if(this.getFps().length()>0){
			text+="#export_fps="+this.getFps();
		}else{
			text+="#export_fps="+"15";
		}
		text+="\n";
		text+=toTextDougaText();
		view.setText(text);
		view.updateUndoRedo();
		PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().activate(view);
	}
	
	protected void updateStatus() {
		boolean hasfile=false;
		if(beforeFiles.getFileList()!=null && beforeFiles.getFileList().length>0){
			hasfile=true;
		}
		if(!hasfile){
			Control[] controls=composite.getChildren();
		
			for (int i = 0; i < controls.length; i++) {
				SubtitleData sdata=(SubtitleData) controls[i];
				if(sdata.getInsideFiles().getFileList()!=null && sdata.getInsideFiles().getFileList().length>0||sdata.getAfterFiles().getFileList()!=null && sdata.getAfterFiles().getFileList().length>0){
					hasfile=true;
					break;
				}
			}
		}
		//getWizard().
		if(hasfile){
			execButton.setEnabled(true);
		}else{
			execButton.setEnabled(false);
		}
	}
	
	public String toTextDougaText(){
		SyncSubBuilder builder=new SyncSubBuilder();
		builder.setAudioOffset(offsetTime.getTime());
		builder.setFfmpegPath(FFMpegUI.getFFmpegOrPureFFMpeg());
		String text="";
		
		
		//set audio path
		if(!inputAudio.getAbsoluteFilePath().equals("")){
			//set offset time if 
			if(offsetTime.getTime()!=0){
				text+="#start="+(offsetTime.getTime()/1000.0)+"\n";
			}
			text+=inputAudio.getAbsoluteFilePath()+"\n";
			builder.setAudioPath(inputAudio.getAbsoluteFilePath());
		}else{
			builder.setAudioPath(null);
		}
		
		text+="#default,fadein=0,fadeout=0";//TODO support change
		if(this.getSize().length()>0){ //now force resize
			String[] wh=this.getSize().split("x");
			if(wh.length>1){
				text+=",width="+wh[0]+",height="+wh[1];
			}
		}
		text+="\n";
		builder.setBeforeFiles(beforeFiles.getFileList());
		
		Control[] controls=composite.getChildren();
		List<SyncImageData> syncImageDataList=new ArrayList<SyncImageData>();
		for(int i=0;i<controls.length;i++){
			SubtitleData sdata=(SubtitleData) controls[i];
			syncImageDataList.add(new SyncImageData(sdata.getData(),sdata.getInsideFiles().getFileList(),sdata.getAfterFiles().getFileList()));
		}
		builder.setSyncImageDatas(syncImageDataList);
		List<ResultData> resultDatas=builder.buildText();
		
		for(int i=0;i<resultDatas.size();i++){
			text+=resultDatas.get(i).toString();
		}
		
		text+=toSaveText();
		return text;
	}
	


	
	public class SubtitleData extends Composite{
		
		private EditableFileList insideFiles;
		private EditableFileList afterFiles;
		private Label startTime;
		private Label text;
		private Label endTime;
		StandardSubObject data;
		public SubtitleData(Composite parent, int style) {
			super(parent, style);
			this.setLayout(new GridLayout());
			this.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			text = new Label(this,SWT.BORDER);
			text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			
			Composite centerSplit=WidgetBuilder.createGridLayoutComposite(this, SWT.NULL, 2, true);
			centerSplit.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			Composite files1=WidgetBuilder.createGridLayoutComposite(centerSplit, SWT.NULL, 2, false);
			Composite files2=WidgetBuilder.createGridLayoutComposite(centerSplit, SWT.NULL, 2, false);
			files1.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			files2.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			Composite timeAndImage=WidgetBuilder.createGridLayoutComposite(files1, SWT.NULL);
			startTime = new Label(timeAndImage,SWT.NULL);
			//startTime.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));


			
			Label imgLabel=new Label(timeAndImage,SWT.BORDER);
			insideFiles = WidgetBuilder.createFileList(files1,SWT.NULL,"*.gif;*.png;*.jpg;*.bmp");
			insideFiles.setShowNameOnly(true);
			insideFiles.setLayoutData(LayoutDataBuilder.hintGridData(-1, -1));
			insideFiles.addPropertyChangeListener(new IPropertyChangeListener(){
				public void propertyChange(PropertyChangeEvent event) {
					updateStatus();
				}});
			
			imgLabel.setLayoutData(LayoutDataBuilder.hintGridData(imgWidth, imgHeight));
			UpdateLabelListener labelListener=new UpdateLabelListener(insideFiles,imgLabel);
			insideFiles.addPropertyChangeListener(labelListener);
			insideFiles.addSelectionChangedListener(labelListener);
			Composite timeAndImage2=WidgetBuilder.createGridLayoutComposite(files2, SWT.NULL);
			
			endTime = new Label(timeAndImage2,SWT.NULL);
			//endTime.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			
			Label imgLabel2=new Label(timeAndImage2,SWT.BORDER);
			afterFiles = WidgetBuilder.createFileList(files2,SWT.NULL,"*.gif;*.png;*.jpg;*.bmp");
			afterFiles.setLayoutData(LayoutDataBuilder.hintGridData(-1, -1));
			afterFiles.setShowNameOnly(true);
			afterFiles.addPropertyChangeListener(new IPropertyChangeListener(){
				
				public void propertyChange(PropertyChangeEvent event) {
					updateStatus();
				}});
			
			imgLabel2.setLayoutData(LayoutDataBuilder.hintGridData(imgWidth, imgHeight));
			UpdateLabelListener labelListener2=new UpdateLabelListener(afterFiles,imgLabel2);
			afterFiles.addPropertyChangeListener(labelListener2);
			afterFiles.addSelectionChangedListener(labelListener2);
		}
		


		public void setData(StandardSubObject subObject){
			text.setText(subObject.getText());
			startTime.setText(TimeUtils.toTimeText(subObject.getStartTime()));
			endTime.setText(TimeUtils.toTimeText(subObject.getEndTime()));
			data=subObject;
		}

		public StandardSubObject getData() {
			return data;
		}

		public EditableFileList getInsideFiles() {
			return insideFiles;
		}

		public EditableFileList getAfterFiles() {
			return afterFiles;
		}
		
	}
	
	public double toDouble(String num,double defaultValue){
		if(num==null){
			return defaultValue;
		}
		double ret=defaultValue;
		try{
			ret=Double.parseDouble(num);
		}catch(Exception e){};
		System.out.println(ret);
		return ret;
	}
	
	
	


	
	private CCombo createCCombo(Composite parent,String label,String values[],int style){
		
		Composite p2=WidgetBuilder.createTwoGridLayoutComposite(parent, SWT.NULL);
		WidgetBuilder.createLabel(p2, label);
		CCombo combo=new CCombo(p2,style);
		combo.setLayoutData(LayoutDataBuilder.hintGridData(100, 0));
		
		for (int i = 0; i < values.length; i++) {
			combo.add(values[i]);
		}
		return combo;
	}
	@Override
	public void setFocus() {
		// TODO Auto-generated method stub
		
	}
	public void  loadText(String text){
		String lines[]=text.split("\n");
		boolean header=false;
		int index=0;
		Control[] controls=null;
		for (int i = 0; i < lines.length; i++) {
			if(header==false){
			if(lines[i].startsWith(";#syncsub")){
				header=true;
				String[] paths=lines[i].split(",");
				inputAudio.setFilePath(paths[1]);
				if(paths[2].length()>0){
				inputSubtitle.setFilePath(paths[2]);
				loadSubtitleFile();
				
				}
				if(paths.length>2){//have special params
					String last=lines[i].substring(paths[0].length()+paths[1].length()+2);
					Map<String,String> map=ParserUtils.lineToMap(last,"");
					if(map.get("start")!=null){
						double startTime=PropertyUtils.getDoubleValue(map.get("start"), 0);
						offsetTime.setValue(""+startTime);
					}else{
						offsetTime.setValue(""+0);
					}
				}
				i++;
				controls=composite.getChildren();
				//System.out.println(lines[i]);
				beforeFiles.clear();
				String befores[]=lines[i].split(";");
				for (int j = 0; j < befores.length; j++) {
					if(befores[j].length()>0){
					beforeFiles.addFilePath(befores[j]);
					}
				}
			}
			}else{
				if(lines[i].startsWith(";")){
					String tmp=lines[i].substring(1);
					
					String[] in_af=tmp.split(",");
					if(controls!=null && controls.length>index && in_af.length>0){
					String insides[]=in_af[0].split(";");
					for (int j = 0; j < insides.length; j++) {
						SubtitleData sdata=(SubtitleData) controls[index];
						if(insides[j].length()>0){
						sdata.getInsideFiles().addFilePath(insides[j]);
						sdata.layout();
						}
					}
					if(in_af.length>1){ //case ; only line
					String afters[]=in_af[1].split(";");
					for (int j = 0; j < afters.length; j++) {
						SubtitleData sdata=(SubtitleData) controls[index];
						if(afters[j].length()>0){
						sdata.getAfterFiles().addFilePath(afters[j]);
						sdata.layout();
						}
					}
					}
					}
					index++;
				}
			}
		}
	}
	public String toSaveText(){
		String text=";#syncsub1.0,";
		//option values
		String options="";
		if(offsetTime.getTime()!=0){
			options+=",start="+offsetTime.getTime()/1000.0;
		}
		
		text+=inputAudio.getAbsoluteFilePath()+","+inputSubtitle.getAbsoluteFilePath()+options+"\n";
		
		String befores="";
		File[] file=beforeFiles.getFileList();
		for (int j = 0; j < file.length; j++) {
			befores+=file[j].getAbsolutePath();
			if(j!=file.length-1){
				befores+=";";
			}
		}
		text+=";"+befores+"\n";
		
		Control[] controls=composite.getChildren();
		for(int i=0;i<controls.length;i++){
			SubtitleData sdata=(SubtitleData) controls[i];
			String insides="";
			if(sdata.getInsideFiles().getFileList()!=null){
				File[] files=sdata.getInsideFiles().getFileList();
				for (int j = 0; j < files.length; j++) {
					insides+=files[j].getAbsolutePath();
					if(j!=files.length-1){
						insides+=";";
					}
				}
			}
			String afters="";
			if(sdata.getAfterFiles().getFileList()!=null){
				File[] files=sdata.getAfterFiles().getFileList();
				for (int j = 0; j < files.length; j++) {
					afters+=files[j].getAbsolutePath();
					if(j!=files.length-1){
						afters+=";";
					}
				}
			}
			text+=";"+insides+","+afters+"\n";
		}
		return text;
	}
}
